import sys
from pathlib import Path

file = Path(__file__).resolve()
parent, top = file.parent, file.parents[2]

sys.path.append(str(top))
try:
    sys.path.remove(str(parent))
except ValueError: # Already removed
    pass

# import src.job
__package__ = 'src.job'


from ..model.infer import Lot, InferPanelImage, ScpJob, InferPanel
from ..utils.database import InferSessionLocal
from ..config import clear_size, clear_day, log_dir
from datetime import datetime, timedelta
import shutil
import os
from ..config import thumb_dir, lot_dir, out_dir
import schedule
import time
import psutil
from sqlalchemy import func
from ..utils.log import logger
import re
import threading


class ClearLotJob(object):
    def __init__(self):
        self.stop = threading.Event()
        self.task = None


    def clear_file_by_time(self, day):
        logger.info(">>>>>>>>>>>>>按时间，开始执行清理脚本<<<<<<<<<<<<<<<")

        self.clear_log(day)

        with InferSessionLocal() as session:

            lots = session.query(Lot).filter(Lot.start_time < (datetime.now() - timedelta(day))).all()

            for lot in lots:
                logger.info("删除超过 %s 天的 lot, lot_name: %s, start_time: %s" % (day, lot.lot_name, lot.start_time))

                self.clear_lot_file(lot, session)


    def clear_lot_file(self, lot, session):
        des_lot_dir = lot.dir_path
        out_lot_dir = des_lot_dir.replace(lot_dir, out_dir)
        thumb_folder = des_lot_dir.replace(lot_dir, thumb_dir)

        # 删除存放 lot 的原图
        if os.path.exists(des_lot_dir):
            shutil.rmtree(des_lot_dir)
        # 删除推理的小图
        if os.path.exists(out_lot_dir):
            shutil.rmtree(out_lot_dir)
        # 删除 lot 原图的缩略图
        if os.path.exists(thumb_folder):
            shutil.rmtree(thumb_folder)

        session.query(Lot).filter(Lot.lot_code == lot.lot_code).delete()
        # 删除数据库中的 panel image
        session.query(InferPanel).filter(InferPanel.lot_code == lot.lot_code).delete()
        # 删除数据库中的 failure image
        session.query(InferPanelImage).filter(InferPanelImage.lot_code == lot.lot_code).delete()
        session.query(ScpJob).filter(ScpJob.lot_code == lot.lot_code).delete()
        session.commit()



    def clear_file_by_size(self, size):
        logger.info(">>>>>>>>>>>>按容量，开始执行清理脚本<<<<<<<<<<<<<<<")

        self.clear_log()

        with InferSessionLocal() as session:

            # 对 start_time 进行按日期分组, 同一天的会放在一组
            # 日期默认是升序，先删除较早日期的
            # all_start_time = session.query(func.date_format(Lot.start_time, '%Y-%m-%d').label('date')).group_by('date').order_by(desc('date')).all()
            all_start_time = session.query(func.date_format(Lot.start_time, '%Y-%m-%d').label('date')).group_by('date').all()

            for start_time in all_start_time:
                start_time = start_time[0]
                lots_codes = session.query(Lot.lot_code).filter(func.date_format(Lot.start_time, '%Y-%m-%d')==start_time).all()

                diskuse = psutil.disk_usage('/data')
                not_used_size = int(diskuse[2] / (1024.0 * 1024.0 * 1024.0))

                # 如果磁盘容量不够 4t 开始清理
                is_clear = not_used_size < size

                if is_clear:
                    # 按天删除 lot
                    for lot_id in lots_codes:
                        lot = session.query(Lot).filter(Lot.lot_code==lot_id[0]).first()
                        logger.info(f"磁盘容量为 {not_used_size}G 不足 {size}G, 删除 lot, lot_name: {lot.lot_name}, start_time: {lot.start_time}")
                        
                        self.clear_lot_file(lot, session)


    def clear_file_by_error(self):
        logger.info(">>>>>>>>>>>>按 lot 错误，开始执行清理脚本<<<<<<<<<<<<<<<")

        with InferSessionLocal() as session:
            lots = session.query(Lot).all()

            for lot in lots:
            # 删除推理报错的 lot
                if lot.status == "2":
                    logger.info(f"删除 报错 的 lot, lot_name: {lot.lot_name}")

                    self.clear_lot_file(lot, session)


    def clear_file_by_manual(self):
    
        logger.info(">>>>>>>>>>>>按 lot 错误，开始执行清理脚本<<<<<<<<<<<<<<<")

        with InferSessionLocal() as session:
            lots = session.query(Lot).all()

            complete_lot = []
            complete_lot_code = []


            # 清理未完成的 lot
            for lot in lots:
                # 删除推理报错的 lot
                if lot.status == "2":
                    logger.info(f"删除 报错 的 lot, lot_name: {lot.lot_name}")

                    des_lot_dir = lot.dir_path
                    out_lot_dir = des_lot_dir.replace(lot_dir, out_dir)
                    thumb_folder = des_lot_dir.replace(lot_dir, thumb_dir)

                    # 删除存放 lot 的原图
                    if os.path.exists(des_lot_dir):
                        shutil.rmtree(des_lot_dir)
                    # 删除推理的小图
                    if os.path.exists(out_lot_dir):
                        shutil.rmtree(out_lot_dir)
                    # 删除 lot 原图的缩略图
                    if os.path.exists(thumb_folder):
                        shutil.rmtree(thumb_folder)

                    session.query(Lot).filter(Lot.lot_code == lot.lot_code).delete()
                    # 删除数据库中的 panel image
                    session.query(InferPanel).filter(InferPanel.lot_code == lot.lot_code).delete()
                    # 删除数据库中的 failure image
                    session.query(InferPanelImage).filter(InferPanelImage.lot_code == lot.lot_code).delete()
                    session.query(ScpJob).filter(ScpJob.lot_code.lot_code == lot.lot_code).delete()

                    session.commit()
                else:
                    complete_lot.append(lot.dir_path.replace(lot_dir+"/", ""))
                    complete_lot_code.append(lot.lot_code)

            # 删除手动删除数据库中的lot 其它表数据
            session.query(InferPanel).filter(InferPanel.lot_code.not_in(complete_lot_code)).delete()
            # 删除数据库中的 failure image
            session.query(InferPanelImage).filter(InferPanelImage.lot_code.not_in(complete_lot_code)).delete()
            session.commit()

        #  删除手动删除数据库中的lot 而没有删除 outdir 和 thumbdir 里面的数据
        for folder in os.listdir(lot_dir):
            if folder not in complete_lot:
                logger.info(f"删除 {lot_dir} 中的 lot, lot_name: {folder}")
                shutil.rmtree(os.path.join(lot_dir, folder))

        for folder in os.listdir(out_dir):
            if folder not in complete_lot:
                logger.info(f"删除 {out_dir} 中的 lot, lot_name: {folder}")
                shutil.rmtree(os.path.join(out_dir, folder))

        for folder in os.listdir(thumb_dir):
            if folder not in complete_lot:
                logger.info(f"删除 {thumb_dir} 中的 lot, lot_name: {folder}")
                shutil.rmtree(os.path.join(thumb_dir, folder))


    # 定时清理过期 log
    def clear_log(self, day=15):
        expire_date = (datetime.now()-timedelta(day))

        for file_name in os.listdir(log_dir):

            file_path = os.path.join(log_dir, file_name)

            # 解析文件名中的日期
            # 使用正则表达式提取日期
            match = re.search(r'App_(\d{4}-\d{2}-\d{2}).log', file_name)

            if match:
                file_date_str = match.group(1)
                file_date = datetime.strptime(file_date_str, "%Y-%m-%d")
                if(file_date < expire_date):
                    os.remove(file_path)
                    logger.info(f"删除过期日志 {file_name}")


    def clear(self, ctype):
        logger.info("运行 clear.........")
        # 取消 schedule 里面的 clear 任务
        if self.task:
            schedule.cancel_job(self.task)
        if ctype == 0:
            # 每天 0 点执行一次
            self.task = schedule.every().day.at("00:00").do(self.clear_file_by_time, day=clear_day)
            # 每 1 个小时执行一次
            # schedule.every(3600).seconds.do(clear_file_by_time, day=clear_day)
        elif ctype == 1:
            self.task = schedule.every().day.at("00:00").do(self.clear_file_by_size, size=clear_size)
        elif ctype == 2:
            # 删除推理出错的 lot
            self.task = schedule.every().day.at("00:00").do(self.clear_file_by_error)
        elif ctype == 3:
            # 手动删除 lot
            self.task = schedule.every().day.at("00:00").do(self.clear_file_by_manual)

        schedule.run_all()

        # 如果清理任务没有取消
        while not self.stop.is_set():
            schedule.run_pending()
            time.sleep(1)


if __name__ == "__main__":
    clear_job = ClearLotJob()

    # clear_job.clear()
    # clear_job.clear_file_by_time(30)
    clear_job.clear_file_by_manual()

    






    
